package com.hadwinling.alogriithm.algorithm.pso;



import java.util.Date;
import java.util.Random;


/**
 * @description:
 * @author: hadwinling
 * @time: 2020/12/30 下午3:28
 */
public class JavaPSO {
    static int M = 200;// 迭代次数
    static int numParticles = 50; //粒子数量
    static int dimension = 3;// 粒子的维数

    static double[][] pBest = new double[numParticles][dimension]; // 存储粒子的历史最优位置信息
    static double[][] xPos = new double[numParticles][dimension];// 存储粒子的当前的位置信息
    static double[][] xVel = new double[numParticles][dimension];//存储各粒子的速度信息

    static double[] gBest = new double[dimension];//存储全局最优解对应的位置信息
    static double[] fitness = new double[numParticles];//存储各粒子的适应值

    static double w = 0.5; //惯性因子
    static double c1 = 2.0;
    static double c2 = 2.0;
    static double xMax = 10;
    static double xMin = -10;
    static double vMax = 5;
    static double vMin = -5;

    static Random random = new Random();

    public static void main(String[] args) {
        Date start = new Date();
        Search();
        Date end = new Date();
        System.out.println("时间："+start);
        System.out.println("时间："+end);



    }

    /**
     * 适应值的计算公式
     *
     * @param temp
     * @return
     */
    public static double calcFitness(double[] temp) {
        double y = 0;
        for (int i = 0; i < dimension; i++) {
            y += temp[i] * temp[i];
        }
        return y;
    }

    public static void Initialize() {
        //初始化位置和速度
        for (int i = 0; i < numParticles; i++) {
            for (int j = 0; j < dimension; j++) {
                // 随机产生范围内的位置和速度维度值
                xPos[i][j] = xMin + random.nextDouble() * (xMax - xMin);
                xVel[i][j] = vMin + random.nextDouble() * (vMax - vMin);
            }
        }
        //计算每个粒子的适应值，并初始化局部和全局最优解
        for (int i = 0; i < numParticles; i++) {
            fitness[i] = calcFitness(xPos[i]);
            for (int j = 0; j < dimension; j++) {
                pBest[i][j] = xPos[i][j];
            }
        }
        // 初始化最优适应值对应的位置gBest
        double bestFitness = fitness[0];
        boolean isChange = false;
        for (int i = 1; i < numParticles; i++) {
            if (fitness[i] < bestFitness) {
                isChange = true;
                bestFitness = fitness[i];
                for (int j = 0; j < dimension; j++) {
                    gBest[j] = xPos[i][j];
                }
            }
        }
        if (isChange == false) {
            for (int i = 0; i < dimension; i++) {
                gBest[i] = xPos[0][i];
            }
        }
        //输出初始化提示信息
        System.out.println("初始化完毕！");
        System.out.print("0 ----> " + calcFitness(gBest) + " ----> [");
        for (int i = 0; i < dimension; i++) {
            System.out.print(gBest[i] + ", \t");
        }
        System.out.println("]");
    }


    //算法主体
    public static void Search() {
        Initialize();
        for (int m = 0; m < M; m++) {

            for (int n = 0; n < numParticles; n++) {
                //更新计算出粒子的速度和位置
                for (int d = 0; d < dimension; d++) {
                    xVel[n][d] = w * xVel[n][d] + c1 * random.nextDouble() * (pBest[n][d] - xPos[n][d]) + c2 * random.nextDouble() * (gBest[d] - xPos[n][d]);
                    xPos[n][d] = xPos[n][d] + xVel[n][d];
                }

                //将粒子新的位置对应的适应值与原先适应值相比较，如果新位置的适应值较小，则更新此粒子历史最优位置
                if (calcFitness(xPos[n]) < fitness[n]) {
                    fitness[n] = calcFitness(xPos[n]);
                    for (int d = 0; d < dimension; d++) {
                        pBest[n][d] = xPos[n][d];
                    }
                }

                // 判断是否需要更新全局最优位置
                if (fitness[n] < calcFitness(gBest)) {
                    for (int d = 0; d < dimension; d++) {
                        gBest[d] = pBest[n][d];
                    }
                }

            }

            // 输出这一迭代步骤完成后全局的最优值以及相对应的位置信息
            System.out.print((m + 1) + " ----> " + calcFitness(gBest) + " ----> [");
            for (int i = 0; i < dimension; i++) {
                System.out.print(gBest[i] + ", \t");
            }
            System.out.println("]");

        }

    }


}
